﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection.Emit;
using System.Reflection;

namespace Pixysoft.Reflection
{
    public class ILInstruction
    {
        private OpCode code;
        private object operand;
        private byte[] operandData;
        private int offset;

        public ILInstruction()
        {
        }


        /// <summary>
        /// 获取指令的类型
        /// </summary>
        public ILInstructionType InstructionType
        {
            get
            {
                if (operand == null)
                    return ILInstructionType.Unknown;


                switch (code.OperandType)
                {
                    case OperandType.InlineField:
                        return ILInstructionType.Field;

                    case OperandType.InlineMethod:
                        {
                            if (operand is System.Reflection.MethodInfo)
                            {
                                return ILInstructionType.Method;
                            }
                            else if (operand is System.Reflection.ConstructorInfo)
                            {
                                return ILInstructionType.Ctor;
                            }
                            else
                            {
                                return ILInstructionType.Unknown;
                            }
                        }

                    case OperandType.ShortInlineBrTarget:
                    case OperandType.InlineBrTarget:
                        return ILInstructionType.Unknown;

                    case OperandType.InlineType:
                        return ILInstructionType.Unknown;

                    case OperandType.InlineString:
                        return ILInstructionType.String;

                    case OperandType.ShortInlineVar:
                        return ILInstructionType.Variable;

                    case OperandType.InlineI:
                    case OperandType.InlineI8:
                    case OperandType.InlineR:
                    case OperandType.ShortInlineI:
                    case OperandType.ShortInlineR:
                        return ILInstructionType.Number;

                    case OperandType.InlineTok:
                        return ILInstructionType.Reference;
                }


                return ILInstructionType.Unknown;
            }
        }

        /// <summary>
        /// 获取对应的方法
        /// </summary>
        /// <returns></returns>
        public MethodInfo GetMethodInfo()
        {
            if (operand == null)
                return null;

            if (InstructionType == ILInstructionType.Method)
                return (System.Reflection.MethodInfo)operand;

            return null;
        }

        /// <summary>
        /// 获取构造函数
        /// </summary>
        /// <returns></returns>
        public ConstructorInfo GetConstructorInfo()
        {
            if (operand == null)
                return null;

            if (InstructionType == ILInstructionType.Ctor)
                return (System.Reflection.ConstructorInfo)operand;

            return null;
        }

        /// <summary>
        /// 获取域反射
        /// </summary>
        /// <returns></returns>
        public FieldInfo GetFieldInfo()
        {
            if (operand == null)
                return null;

            if (InstructionType == ILInstructionType.Field)
                return ((System.Reflection.FieldInfo)operand);

            return null;
        }

        /// <summary>
        /// 获取属性
        /// </summary>
        /// <returns></returns>
        public string GetString()
        {
            return operand.ToString();
        }


        /// <summary>
        /// Add enough zeros to a number as to be represented on 4 characters
        /// </summary>
        /// <param name="offset">
        /// The number that must be represented on 4 characters
        /// </param>
        /// <returns>
        /// </returns>
        private string GetExpandedOffset(long offset)
        {
            string result = offset.ToString();
            for (int i = 0; result.Length < 4; i++)
            {
                result = "0" + result;
            }
            return result;
        }


        public OpCode Code
        {
            get { return code; }
            set { code = value; }
        }

        public object Operand
        {
            get { return operand; }
            set { operand = value; }
        }

        public byte[] OperandData
        {
            get { return operandData; }
            set { operandData = value; }
        }

        public int Offset
        {
            get { return offset; }
            set { offset = value; }
        }

        public override string ToString()
        {
            return string.Format("{0} {1} {2}", offset, code.ToString(), operand);
        }
    }

    public enum ILInstructionType
    {
        Unknown,

        /// <summary>
        /// 内部调用的对象
        /// </summary>
        Field,
        /// <summary>
        /// 内部调用的方法
        /// </summary>
        Method,
        /// <summary>
        /// 内部调用的构造函数方法
        /// </summary>
        Ctor,
        /// <summary>
        /// 内部调用的字符串
        /// </summary>
        String,
        /// <summary>
        /// [没有确定]内部调用的值对象
        /// </summary>
        Number,
        /// <summary>
        /// [没有确定]内部调用的变量
        /// </summary>
        Variable,
        /// <summary>
        /// [没有确定]内部调用的引用
        /// </summary>
        Reference,


        /// <summary>
        /// 集合初始化
        /// </summary>
        ArrayCtor,
        /// <summary>
        /// 对比表达式
        /// </summary>
        Compare,
        /// <summary>
        /// 加载值对象
        /// </summary>
        LoadValue,
        /// <summary>
        /// 加载数组
        /// </summary>
        LoadArray,
        /// <summary>
        /// 根据位置 加载本地变量
        /// </summary>
        LoadLocalVariable,
    }
}
